﻿using System;
using System.Net;
using System.Xml;
using System.Xml.Linq;
using Communergy.Common;
using Communergy.Common.Events;
using Communergy.Data;
using Microsoft.Http;
using Microsoft.Http.Headers;

namespace Communergy.Powermeter
{
    public class GooglePowermeterExportCommand : IDataExportCommand
    {
        #region Fields (5)

        TimeSpan ageOfRecords;
        IRepositoryFactory cacheRepository;
        DateTime lastUploadDateTime = DateTime.Now;
        string meterId;
        PowermeterData powerMeterData;

        #endregion Fields

        #region Constructors (1)

        public GooglePowermeterExportCommand(string meterId, TimeSpan ageOfRecords, PowermeterData powerMeterData)
        {
            this.meterId = meterId;

            this.ageOfRecords = ageOfRecords;
            this.powerMeterData = powerMeterData;
            this.ExportInterval = ageOfRecords;

        }

        #endregion Constructors

        #region Properties (3)

        public TimeSpan AgeOfRecords
        {
            get { return ageOfRecords; }
            set { ageOfRecords = value; }
        }

        public TimeSpan ExportInterval { get; set; }

        public IRepositoryFactory LocalCacheRepository { get; set; }

        #endregion Properties

        #region Delegates and Events (1)

        // Events (1) 

        public event DataExportHandler DataExportEvent;

        #endregion Delegates and Events

        #region Methods (9)

        // Public Methods (5) 

        public void ExportData()
        {
            ExportToPowermeter();
        }

        public void ExportData(string exportXml)
        {
            string url = GetPostUrl();
            string authToken = this.powerMeterData.AuthToken;
            PostXml(url, exportXml, authToken);
        }

        public static string GetExportXml(HistoricalEnergyReading exportData)
        {
            XNamespace atomNamespace = "http://www.w3.org/2005/Atom";
            XNamespace googleNamespace = "http://schemas.google.com/meter/2008";

            var entry = new XElement(atomNamespace + "entry",
                //new XAttribute("meter", googleNamespace),
                    new XElement(googleNamespace + "startTime", exportData.ReadingDateTime,
                        new XAttribute(googleNamespace + "uncertainty", "1.0")
                    ),
                    new XElement(googleNamespace + "endTime", exportData.ReadingDateTime.Add(exportData.TimeSpan),
                        new XAttribute(googleNamespace + "uncertainty", "1.0")
                        )
                    ,
                    new XElement(googleNamespace + "quantity", exportData.KWh,
                        new XAttribute(googleNamespace + "uncertainty", "1.0"), new XAttribute(googleNamespace + "unit", "kW h")
                     )
                     )
                    ;
            entry.SetAttributeValue(XNamespace.Xmlns + "meter", googleNamespace);
            return entry.ToString();
        }

        public string GetPostUrl()
        {
            string url = this.powerMeterData.UserDeviceBaseUrl;
            return url;
        }

        public static HttpStatusCode PostXml(string url, string xml, string authToken)
        {
            string response = string.Empty;
            string authSubHeader = string.Format("AuthSub token=\"{0}\"", authToken);
            string contentType = "application/atom+xml";
            var bytes = System.Text.Encoding.ASCII.GetBytes(xml);

            try
            {
                using (HttpClient client = new HttpClient())
                {
                    client.TransportSettings.ConnectionTimeout = new TimeSpan(0, 0, 4);
                    client.TransportSettings.ReadWriteTimeout = new TimeSpan(0, 0, 4);
                    RequestHeaders headers = new RequestHeaders();
                    headers.ContentType = contentType;
                    headers.Add("Authorization", authSubHeader);
                    HttpContent content = HttpContent.Create(bytes);
                    HttpResponseMessage resp = client.Send(HttpMethod.POST, url, headers, content);
                    return resp.StatusCode;
                }


            }
            catch (WebException we)
            {
                return HttpStatusCode.ExpectationFailed;
            }
            catch (Exception ex)
            {
                return HttpStatusCode.ExpectationFailed;
            }


        }
        // Private Methods (4) 

        private void ExportToPowermeter()
        {
            HistoricalEnergyReading exportData = GetDurationalData();
            if (exportData != null)
            {
                string exportXml = GetExportXml(exportData);
                ExportData(exportXml);

                string updateData = string.Format("Google Powermeter: Exported {0:0.000} kWh from between {1} and {2}", exportData.KWh, exportData.ReadingDateTime.ToString(), exportData.ReadingDateTime.Add(exportData.TimeSpan).ToString());
                UpdateStatus(updateData);
            }
        }

        private HistoricalEnergyReading GetDurationalData()
        {
            DataAccessLayer dataAccess = new DataAccessLayer(LocalCacheRepository);
            DateTime dateTo = DateTime.Now;
            DateTime dateFrom = dateTo.Subtract(ageOfRecords);
            HistoricalEnergyReading historicalReading = dataAccess.GetCumulativeElectricityRealtime(meterId, dateFrom, dateTo);
            return historicalReading;
        }

        private void RaiseNewDataExportEvent(DataExporterEventArgs de)
        {
            if (DataExportEvent != null)
            {
                DataExportEvent(this, de);
            }
        }

        private void UpdateStatus(string message)
        {
            DataExporterEventArgs de = new DataExporterEventArgs();
            de.Message = message;
            RaiseNewDataExportEvent(de);
        }

        #endregion Methods
    }
}
